package com.itttq.im.service;

import com.itttq.im.dao.es.MsgDao;
import com.itttq.im.model.qo.MsgQo;
import com.itttq.im.model.to.MsgTo;
import com.itttq.im.model.to.PageTo;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.UUID;

@Service
public class MsgService {
    @Autowired
    private MsgDao msgDao;

    public Iterable<MsgTo> findAll() {
        return msgDao.findAll();
    }

    public void save(MsgTo msg) {
        msg.setId(UUID.randomUUID().toString());
        msg.setCreateTime(new Date());
        msgDao.save(msg);
    }

    public PageTo<MsgTo> findMsg(MsgQo msgQo) {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        Pageable pageable = PageRequest.of(msgQo.getPageNo(), msgQo.getPageSize(), sort);
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder().withPageable(pageable);
        queryBuilder.withQuery(buildBasicQuery(msgQo));
        Page<MsgTo> msgPage = msgDao.search(queryBuilder.build());
        PageTo<MsgTo> pageTo = new PageTo<>();
        pageTo.setTotal(msgPage.getTotalElements());
        pageTo.setData(msgPage.getContent());
        return pageTo;
    }

    /**
     * 构建基本查询。
     * QueryBuilders这个类封装的基本查询
     * <p>
     * QueryBuilders.matchQuery() 会根据分词器进行分词，分词之后去查询
     * QueryBuilders.termQuery() 不会进行分词，且完全等于才会匹配
     * QueryBuilders.termsQuery() 一个字段匹配多个值，where name = ‘A’ or name = ‘B’
     * QueryBuilders.multiMatchQuery() 会分词 一个值对应多个字段 where username = ‘zs’ or password = ‘zs’
     * QueryBuilders.matchPhraseQuery() 不会分词，当成一个整体去匹配，相当于 %like%
     * 如果想使用一个字段匹配多个值，并且这多个值是and关系，如下 要求查询的数据中必须包含北京‘和’天津QueryBuilders.matchQuery(“address”,“北京 天津”).operator(Operator.AND)
     * 如果想使用一个字段匹配多个值，并且这多个值是or关系，如下 要求查询的数据中必须包含北京‘或’天津
     * QueryBuilders.matchQuery(“address”,“北京 天津”).operator(Operator.OR)
     *
     * @param msgQo
     * @return
     */
    private BoolQueryBuilder buildBasicQuery(MsgQo msgQo) {
        // 构建布尔查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (null != msgQo.getType()) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("type", msgQo.getType()));
        }
        if (StringUtils.isNotEmpty(msgQo.getFrom()) && StringUtils.isNotEmpty(msgQo.getTo())) {
            // 因为聊天室相互的，因此一个聊天记录包括的应该是 双向的消息：from-->to、to-->from
            BoolQueryBuilder subBqbFrom = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("from", msgQo.getFrom())).must(QueryBuilders.termQuery("to", msgQo.getTo()));
            BoolQueryBuilder subBqbTo = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("to", msgQo.getFrom())).must(QueryBuilders.termQuery("from", msgQo.getTo()));
            boolQueryBuilder.filter(QueryBuilders.boolQuery().should(subBqbFrom).should(subBqbTo));
            return boolQueryBuilder;
        }
        if (StringUtils.isNotEmpty(msgQo.getFrom())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("from", msgQo.getFrom()));
        }
        if (StringUtils.isNotEmpty(msgQo.getTo())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("to", msgQo.getTo()));
        }
        return boolQueryBuilder;
    }
}
